package com.example.mytestdemo.launch

import android.util.Log
import androidx.lifecycle.lifecycleScope
import com.example.mytestdemo.BaseViewBindActivity
import com.example.mytestdemo.R
import com.example.mytestdemo.databinding.ActivityTestLaunchLayoutBinding
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.*
import kotlin.coroutines.CoroutineContext


class TestLaunchActivity : BaseViewBindActivity<ActivityTestLaunchLayoutBinding>() {


    override fun getLayoutInflateId(): Int {
        return R.layout.activity_test_launch_layout
    }

    override fun initData() {


        lifecycleScope.launch (CoroutineName("A")+Dispatchers.IO+ SupervisorJob()){
            Log.d(TAG, "initUI: ${coroutineContext}")
            launch {
                Log.d(TAG, "initUI new : ${coroutineContext}")
                Log.d(TAG, "initUI thread : ${Thread.currentThread().name}")
            }
        }

        val scope = CoroutineScope(CoroutineExceptionHandler(object : (CoroutineContext, Throwable) -> Unit {
            override fun invoke(p1: CoroutineContext, p2: Throwable) {
                Log.e("initUI petterp", "CoroutineExceptionHandler${p2.message}")
            }

        }))
        scope.launch(CoroutineName("A")) {
            launch(  SupervisorJob()) {
                delay(10)
                Log.d(TAG, "initUI 异常 : ${coroutineContext}")
                throw RuntimeException("RuntimeException")
            }
            launch() {
                delay(200)
                Log.d(TAG, "initUI 异常 new : ${coroutineContext}")
                Log.e("initUI petterp", "猜猜我还能不能打印")
            }
        }

        //异常封装的请求
        fetch()

        testRunCatch()
    }


    private fun testRunCatch(){
                val string = "adc"
//        runCatching {
//            Log.e(TAG, "onCreate: ${string.toInt()}")
//        }.getOrNull()

        runCatching {
            Log.e(TAG, "onCreate: ${string.toInt()}")
        }.getOrElse {
            it.printStackTrace()
        }

        runCatching {
            Log.e(TAG, "onCreate 这句会崩溃: ${string.toInt()}")
        }.getOrThrow()


        runCatching {
            Log.e(TAG, "onCreate: ${string.toInt()}")
        }.getOrDefault("aaa")

//        val string = "adc"
//        runCatching {
//            Log.e(TAG, "tgwonCreate: ${string.toInt()}")
//        }
    }

    override fun initUI() {

        //测试MutableSharedFlow的用法及其参数
        testSharedFlow()
//        testSharedFlow2()

//        testFlow()
    }


    private fun testFlow() {
        val flow = flow<Int> {
            (1..5).forEach {
                delay(1000)
                emit(it)
            }
        }

//        lifecycleScope.launch {
//            flow.collect {
//                Log.d(TAG, "testFlow 第一个收集器: 我是冷流：$it")
//            }
//            delay(5000)
//            flow.collect {
//                Log.d(TAG, "testFlow:第二个收集器 我是冷流：$it")
//            }
//        }
//        lifecycleScope.launch {
//            delay(5000)
//            flow.collect {
//                Log.d(TAG, "testFlow:第二个收集器 我是冷流：$it")
//            }
//        }


    }

    private fun testSharedFlow() {
        // * SharedFlow与StateFlow区别 //  https://juejin.cn/post/7054178311076839432

        val sharedFlow = MutableSharedFlow<Int>(
            replay = 0,//相当于粘性数据
            extraBufferCapacity = 0,//接受的慢时候，发送的入栈
            onBufferOverflow = BufferOverflow.SUSPEND
        )
        lifecycleScope.launch {
            launch {

                sharedFlow.collect {
                    //收5个需要1秒，意思是另外五个将有机会在collect2中打印出来，
                    //extraBufferCapacity = 4代表可以发送入栈4个，collect2中只会打印1个
                    println("collect1 received ago shared flow $it")
//                    sharedFlow.resetReplayCache()

                    delay(3000)
                    println("collect1 received after shared flow $it")
                }
            }
            launch {
                //热流，只管发，如果没有注册接受者，replay=0 将后面接收不到
                //当collect收集过慢的时候，emit方法会阻塞后面数据的发送，
                // replay = 0, extraBufferCapacity = 0时
                //日志中的15秒与18秒的过渡日志，就知道了
                //2022-09-07 15:00:15.430 /System.out: emit1  send ago shared flow 1
                //2022-09-07 15:00:15.431 I/System.out: collect1 received ago shared flow 1
                //2022-09-07 15:00:15.455  I/System.out: emit1 send after flow 1
                //2022-09-07 15:00:15.461 I/System.out: emit1  send ago shared flow 2
                //2022-09-07 15:00:18.460 I/System.out: collect1 received after shared flow 1
                //2022-09-07 15:00:18.461  I/System.out: emit1 send after flow 2
                //2022-09-07 15:00:18.461  I/System.out: emit1  send ago shared flow 3
                //2022-09-07 15:00:18.462  I/System.out: collect1 received ago shared flow 2
                (1..5).forEach {
                    println("emit1  send ago  flow $it")
                    sharedFlow.emit(it)
                    println("emit1 send after flow $it")
                    delay(100)
                }
            }
            // wait a minute
            delay(300)
            launch {
                sharedFlow.collect {
                    println("collect2 received shared flow $it")
                }
            }
        }

    }


    private fun testSharedFlow2() {
        val stateFlow = MutableStateFlow<Int>(value = -1)

        val sharedFlow = MutableSharedFlow<Int>(
            replay = 0,//相当于粘性数据
            extraBufferCapacity = 2,//接受的慢时候，发送的入栈
            onBufferOverflow = BufferOverflow.DROP_OLDEST
        )
        lifecycleScope.launch {
            launch {

                stateFlow.collect {
                    println("collect1 received ago shared flow $it")
                    delay(100)
                }
            }
            launch {
                (1..5).forEach {
                    println("emit1  send ago  flow $it")
                    stateFlow.emit(it)
                    delay(100)
                    println("emit1 send after flow $it")
                }
            }
            // wait a minute
            delay(1000)
            launch {
                stateFlow.collect {
                    println("collect2 received shared flow $it")
                }
            }
        }

    }

    override fun onResume() {
        super.onResume()
        lifecycleScope.launch(Dispatchers.IO) {

            mBind.btTest.text = "子线程22${Thread.currentThread().name}"

        }
        //设置该属性子线程更新textview就会崩溃，关键是绕过了 一段方法导致它调用了 requestLayout 方法,在里面做了主线程检测
//        mBind.btTest.ellipsize = TextUtils.TruncateAt.valueOf("MARQUEE")
//
//       android:hardwareAccelerated="false"  AndroidManifest.xml 中的application 的 关闭硬件加速

        //而调用invalidate方法的时候viewgroup的invalidateChild方法，里面的
        //主要是 attachInfo 这个一般onresume后都会成立，下一个就是 是否开启硬件加速。开启了就会导致不会走到后续
//        if (attachInfo != null && attachInfo.mHardwareAccelerated) {
//            // HW accelerated fast path
//            onDescendantInvalidated(child, child);
//            return;
//        }
//        onDescendantInvalidated 方法会递归调用到viewrootimpl中的onDescendantInvalidated方法，
//        这个方法调用本身的invalidate 方法 再到 scheduleTraversals方法绘制流程开始，没有进行过线程检测

//        上面这一段代码会截断后续，防止递归调用，

        //android:hardwareAccelerated="false" 硬件加速关闭后就会抛出主线程检测因为他走到了viewrootimpl中去
//        下面的  parent = parent.invalidateChildInParent(location, dirty);这一段代码
//        会一直调用到viewrootimpl中去

        mBind.btTest.setOnClickListener{
            lifecycleScope.launch(Dispatchers.IO) {
                mBind.btTest.text = "子线程点击改变：${Thread.currentThread().name}"

//                mBind.testIv.setBackgroundResource(R.drawable.aa)
            }

//            Thread{
//              mBind.btTest.text = "子线程点击改变为什么：${Thread.currentThread().name}"
//                mBind.btTest.invalidate()
//            }.start()

        }
    }


    fun fetch() {
        lifecycleScope.rxLaunch<String> {
            onRequest = {
                //网络请求
                Log.d(TAG, "fetch: onRequest")

                getData1()
//                resposity.getData()
            }
            onSuccess = {
                //成功回调
                Log.d(TAG, "fetch:onSuccess ")
            }
            onError = {
                //失败回调
                Log.d(TAG, "fetch: onError")
            }
        }

        var coroutineBuilder = object : CoroutineBuilder<String>() {
            private  val TAG = "TestLaunchActivity"
            override var onRequest: (suspend () -> String)? =  {
                //网络请求
                Log.d(Companion.TAG, "fetch: rxLaunch1 onRequest")

                getData1()
//                resposity.getData()
            }

        }
        lifecycleScope.rxLaunch1<String>(coroutineBuilder)
    }
    val getData1 :() -> String = {
        Log.d(TAG, ":getData1 ")
        ""
    }
    suspend fun getData():String{return ""}

    fun <T> CoroutineScope.rxLaunch(init: CoroutineBuilder<T>.()->Unit) {
        val result = CoroutineBuilder<T>().apply(init)
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
            result.onError?.invoke(exception)
        }
        launch(coroutineExceptionHandler) {
            val res: T? = result.onRequest?.invoke()
            res?.let {
                result.onSuccess?.invoke(it)
            }
        }
    }
    fun <T> CoroutineScope.rxLaunch1(init: CoroutineBuilder<T>) {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
            init.onError?.invoke(exception)
        }
        launch(coroutineExceptionHandler) {
            val res: T? = init.onRequest?.invoke()
            res?.let {
                init.onSuccess?.invoke(it)
            }
        }
    }

    open class CoroutineBuilder<T> {


        open var onRequest: (suspend () -> T)? = null
        open var onSuccess: ((T) -> Unit)? = null
        open var onError: ((Throwable) -> Unit)? = null
    }
}